export default function (module, exports, __webpack_require__) {


    /*
    * Licensed to the Apache Software Foundation (ASF) under one
    * or more contributor license agreements.  See the NOTICE file
    * distributed with this work for additional information
    * regarding copyright ownership.  The ASF licenses this file
    * to you under the Apache License, Version 2.0 (the
    * "License"); you may not use this file except in compliance
    * with the License.  You may obtain a copy of the License at
    *
    *   http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing,
    * software distributed under the License is distributed on an
    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    * KIND, either express or implied.  See the License for the
    * specific language governing permissions and limitations
    * under the License.
    */

    var zrUtil = __webpack_require__("6d8b");

    var RoamController = __webpack_require__("4a01");

    var roamHelper = __webpack_require__("01ef");

    var _cursorHelper = __webpack_require__("c526");

    var onIrrelevantElement = _cursorHelper.onIrrelevantElement;

    var graphic = __webpack_require__("2306");

    var geoSourceManager = __webpack_require__("5b87");

    var _component = __webpack_require__("8918");

    var getUID = _component.getUID;

    var Transformable = __webpack_require__("0cde");

    /*
    * Licensed to the Apache Software Foundation (ASF) under one
    * or more contributor license agreements.  See the NOTICE file
    * distributed with this work for additional information
    * regarding copyright ownership.  The ASF licenses this file
    * to you under the Apache License, Version 2.0 (the
    * "License"); you may not use this file except in compliance
    * with the License.  You may obtain a copy of the License at
    *
    *   http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing,
    * software distributed under the License is distributed on an
    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    * KIND, either express or implied.  See the License for the
    * specific language governing permissions and limitations
    * under the License.
    */
    function getFixedItemStyle(model) {
        var itemStyle = model.getItemStyle();
        var areaColor = model.get('areaColor'); // If user want the color not to be changed when hover,
        // they should both set areaColor and color to be null.

        if (areaColor != null) {
            itemStyle.fill = areaColor;
        }

        return itemStyle;
    }

    function updateMapSelectHandler(mapDraw, mapOrGeoModel, regionsGroup, api, fromView) {
        regionsGroup.off('click');
        regionsGroup.off('mousedown');

        if (mapOrGeoModel.get('selectedMode')) {
            regionsGroup.on('mousedown', function () {
                mapDraw._mouseDownFlag = true;
            });
            regionsGroup.on('click', function (e) {
                if (!mapDraw._mouseDownFlag) {
                    return;
                }

                mapDraw._mouseDownFlag = false;
                var el = e.target;

                while (!el.__regions) {
                    el = el.parent;
                }

                if (!el) {
                    return;
                }

                var action = {
                    type: (mapOrGeoModel.mainType === 'geo' ? 'geo' : 'map') + 'ToggleSelect',
                    batch: zrUtil.map(el.__regions, function (region) {
                        return {
                            name: region.name,
                            from: fromView.uid
                        };
                    })
                };
                action[mapOrGeoModel.mainType + 'Id'] = mapOrGeoModel.id;
                api.dispatchAction(action);
                updateMapSelected(mapOrGeoModel, regionsGroup);
            });
        }
    }

    function updateMapSelected(mapOrGeoModel, regionsGroup) {
        // FIXME
        regionsGroup.eachChild(function (otherRegionEl) {
            zrUtil.each(otherRegionEl.__regions, function (region) {
                otherRegionEl.trigger(mapOrGeoModel.isSelected(region.name) ? 'emphasis' : 'normal');
            });
        });
    }
    /**
     * @alias module:echarts/component/helper/MapDraw
     * @param {module:echarts/ExtensionAPI} api
     * @param {boolean} updateGroup
     */


    function MapDraw(api, updateGroup) {
        var group = new graphic.Group();
        /**
         * @type {string}
         * @private
         */

        this.uid = getUID('ec_map_draw');
        /**
         * @type {module:echarts/component/helper/RoamController}
         * @private
         */

        this._controller = new RoamController(api.getZr());
        /**
         * @type {Object} {target, zoom, zoomLimit}
         * @private
         */

        this._controllerHost = {
            target: updateGroup ? group : null
        };
        /**
         * @type {module:zrender/container/Group}
         * @readOnly
         */

        this.group = group;
        /**
         * @type {boolean}
         * @private
         */

        this._updateGroup = updateGroup;
        /**
         * This flag is used to make sure that only one among
         * `pan`, `zoom`, `click` can occurs, otherwise 'selected'
         * action may be triggered when `pan`, which is unexpected.
         * @type {booelan}
         */

        this._mouseDownFlag;
        /**
         * @type {string}
         */

        this._mapName;
        /**
         * @type {boolean}
         */

        this._initialized;
        /**
         * @type {module:zrender/container/Group}
         */

        group.add(this._regionsGroup = new graphic.Group());
        /**
         * @type {module:zrender/container/Group}
         */

        group.add(this._backgroundGroup = new graphic.Group());
    }

    MapDraw.prototype = {
        constructor: MapDraw,
        draw: function (mapOrGeoModel, ecModel, api, fromView, payload) {
            var isGeo = mapOrGeoModel.mainType === 'geo'; // Map series has data. GEO model that controlled by map series
            // will be assigned with map data. Other GEO model has no data.

            var data = mapOrGeoModel.getData && mapOrGeoModel.getData();
            isGeo && ecModel.eachComponent({
                mainType: 'series',
                subType: 'map'
            }, function (mapSeries) {
                if (!data && mapSeries.getHostGeoModel() === mapOrGeoModel) {
                    data = mapSeries.getData();
                }
            });
            var geo = mapOrGeoModel.coordinateSystem;

            this._updateBackground(geo);

            var regionsGroup = this._regionsGroup;
            var group = this.group;
            var transformInfo = geo.getTransformInfo(); // No animation when first draw or in action

            var isFirstDraw = !regionsGroup.childAt(0) || payload;
            var targetScale;

            if (isFirstDraw) {
                group.transform = transformInfo.roamTransform;
                group.decomposeTransform();
                group.dirty();
            } else {
                var target = new Transformable();
                target.transform = transformInfo.roamTransform;
                target.decomposeTransform();
                var props = {
                    scale: target.scale,
                    position: target.position
                };
                targetScale = target.scale;
                graphic.updateProps(group, props, mapOrGeoModel);
            }

            var scale = transformInfo.rawScale;
            var position = transformInfo.rawPosition;
            regionsGroup.removeAll();
            var itemStyleAccessPath = ['itemStyle'];
            var hoverItemStyleAccessPath = ['emphasis', 'itemStyle'];
            var labelAccessPath = ['label'];
            var hoverLabelAccessPath = ['emphasis', 'label'];
            var nameMap = zrUtil.createHashMap();
            zrUtil.each(geo.regions, function (region) {
                // Consider in GeoJson properties.name may be duplicated, for example,
                // there is multiple region named "United Kindom" or "France" (so many
                // colonies). And it is not appropriate to merge them in geo, which
                // will make them share the same label and bring trouble in label
                // location calculation.
                var regionGroup = nameMap.get(region.name) || nameMap.set(region.name, new graphic.Group());
                var compoundPath = new graphic.CompoundPath({
                    segmentIgnoreThreshold: 1,
                    shape: {
                        paths: []
                    }
                });
                regionGroup.add(compoundPath);
                var regionModel = mapOrGeoModel.getRegionModel(region.name) || mapOrGeoModel;
                var itemStyleModel = regionModel.getModel(itemStyleAccessPath);
                var hoverItemStyleModel = regionModel.getModel(hoverItemStyleAccessPath);
                var itemStyle = getFixedItemStyle(itemStyleModel);
                var hoverItemStyle = getFixedItemStyle(hoverItemStyleModel);
                var labelModel = regionModel.getModel(labelAccessPath);
                var hoverLabelModel = regionModel.getModel(hoverLabelAccessPath);
                var dataIdx; // Use the itemStyle in data if has data

                if (data) {
                    dataIdx = data.indexOfName(region.name); // Only visual color of each item will be used. It can be encoded by dataRange
                    // But visual color of series is used in symbol drawing
                    //
                    // Visual color for each series is for the symbol draw

                    var visualColor = data.getItemVisual(dataIdx, 'color', true);

                    if (visualColor) {
                        itemStyle.fill = visualColor;
                    }
                }

                var transformPoint = function (point) {
                    return [point[0] * scale[0] + position[0], point[1] * scale[1] + position[1]];
                };

                zrUtil.each(region.geometries, function (geometry) {
                    if (geometry.type !== 'polygon') {
                        return;
                    }

                    var points = [];

                    for (var i = 0; i < geometry.exterior.length; ++i) {
                        points.push(transformPoint(geometry.exterior[i]));
                    }

                    compoundPath.shape.paths.push(new graphic.Polygon({
                        segmentIgnoreThreshold: 1,
                        shape: {
                            points: points
                        }
                    }));

                    for (var i = 0; i < (geometry.interiors ? geometry.interiors.length : 0); ++i) {
                        var interior = geometry.interiors[i];
                        var points = [];

                        for (var j = 0; j < interior.length; ++j) {
                            points.push(transformPoint(interior[j]));
                        }

                        compoundPath.shape.paths.push(new graphic.Polygon({
                            segmentIgnoreThreshold: 1,
                            shape: {
                                points: points
                            }
                        }));
                    }
                });
                compoundPath.setStyle(itemStyle);
                compoundPath.style.strokeNoScale = true;
                compoundPath.culling = true; // Label

                var showLabel = labelModel.get('show');
                var hoverShowLabel = hoverLabelModel.get('show');
                var isDataNaN = data && isNaN(data.get(data.mapDimension('value'), dataIdx));
                var itemLayout = data && data.getItemLayout(dataIdx); // In the following cases label will be drawn
                // 1. In map series and data value is NaN
                // 2. In geo component
                // 4. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout

                if (isGeo || isDataNaN && (showLabel || hoverShowLabel) || itemLayout && itemLayout.showLabel) {
                    var query = !isGeo ? dataIdx : region.name;
                    var labelFetcher; // Consider dataIdx not found.

                    if (!data || dataIdx >= 0) {
                        labelFetcher = mapOrGeoModel;
                    }

                    var textEl = new graphic.Text({
                        position: transformPoint(region.center.slice()),
                        // FIXME
                        // label rotation is not support yet in geo or regions of series-map
                        // that has no data. The rotation will be effected by this `scale`.
                        // So needed to change to RectText?
                        scale: [1 / group.scale[0], 1 / group.scale[1]],
                        z2: 10,
                        silent: true
                    });
                    graphic.setLabelStyle(textEl.style, textEl.hoverStyle = {}, labelModel, hoverLabelModel, {
                        labelFetcher: labelFetcher,
                        labelDataIndex: query,
                        defaultText: region.name,
                        useInsideStyle: false
                    }, {
                        textAlign: 'center',
                        textVerticalAlign: 'middle'
                    });

                    if (!isFirstDraw) {
                        // Text animation
                        var textScale = [1 / targetScale[0], 1 / targetScale[1]];
                        graphic.updateProps(textEl, {
                            scale: textScale
                        }, mapOrGeoModel);
                    }

                    regionGroup.add(textEl);
                } // setItemGraphicEl, setHoverStyle after all polygons and labels
                // are added to the rigionGroup


                if (data) {
                    data.setItemGraphicEl(dataIdx, regionGroup);
                } else {
                    var regionModel = mapOrGeoModel.getRegionModel(region.name); // Package custom mouse event for geo component

                    compoundPath.eventData = {
                        componentType: 'geo',
                        componentIndex: mapOrGeoModel.componentIndex,
                        geoIndex: mapOrGeoModel.componentIndex,
                        name: region.name,
                        region: regionModel && regionModel.option || {}
                    };
                }

                var groupRegions = regionGroup.__regions || (regionGroup.__regions = []);
                groupRegions.push(region);
                regionGroup.highDownSilentOnTouch = !!mapOrGeoModel.get('selectedMode');
                graphic.setHoverStyle(regionGroup, hoverItemStyle);
                regionsGroup.add(regionGroup);
            });

            this._updateController(mapOrGeoModel, ecModel, api);

            updateMapSelectHandler(this, mapOrGeoModel, regionsGroup, api, fromView);
            updateMapSelected(mapOrGeoModel, regionsGroup);
        },
        remove: function () {
            this._regionsGroup.removeAll();

            this._backgroundGroup.removeAll();

            this._controller.dispose();

            this._mapName && geoSourceManager.removeGraphic(this._mapName, this.uid);
            this._mapName = null;
            this._controllerHost = {};
        },
        _updateBackground: function (geo) {
            var mapName = geo.map;

            if (this._mapName !== mapName) {
                zrUtil.each(geoSourceManager.makeGraphic(mapName, this.uid), function (root) {
                    this._backgroundGroup.add(root);
                }, this);
            }

            this._mapName = mapName;
        },
        _updateController: function (mapOrGeoModel, ecModel, api) {
            var geo = mapOrGeoModel.coordinateSystem;
            var controller = this._controller;
            var controllerHost = this._controllerHost;
            controllerHost.zoomLimit = mapOrGeoModel.get('scaleLimit');
            controllerHost.zoom = geo.getZoom(); // roamType is will be set default true if it is null

            controller.enable(mapOrGeoModel.get('roam') || false);
            var mainType = mapOrGeoModel.mainType;

            function makeActionBase() {
                var action = {
                    type: 'geoRoam',
                    componentType: mainType
                };
                action[mainType + 'Id'] = mapOrGeoModel.id;
                return action;
            }

            controller.off('pan').on('pan', function (e) {
                this._mouseDownFlag = false;
                roamHelper.updateViewOnPan(controllerHost, e.dx, e.dy);
                api.dispatchAction(zrUtil.extend(makeActionBase(), {
                    dx: e.dx,
                    dy: e.dy
                }));
            }, this);
            controller.off('zoom').on('zoom', function (e) {
                this._mouseDownFlag = false;
                roamHelper.updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);
                api.dispatchAction(zrUtil.extend(makeActionBase(), {
                    zoom: e.scale,
                    originX: e.originX,
                    originY: e.originY
                }));

                if (this._updateGroup) {
                    var scale = this.group.scale;

                    this._regionsGroup.traverse(function (el) {
                        if (el.type === 'text') {
                            el.attr('scale', [1 / scale[0], 1 / scale[1]]);
                        }
                    });
                }
            }, this);
            controller.setPointerChecker(function (e, x, y) {
                return geo.getViewRectAfterRoam().contain(x, y) && !onIrrelevantElement(e, api, mapOrGeoModel);
            });
        }
    };
    var _default = MapDraw;
    module.exports = _default;


}